# -*- coding: utf-8 -*-
"""
    .xfree.admin.views
    ~~~~~~~~~~~~~~~~~~~~~
    文件描述：管理视图相关功能。
    作者：xfree
    邮箱：cy_83k@qq.com
"""
import logging
import sys

# 导入Celery版本号
from celery import __version__ as celery_version
# 导入Flask相关模块和函数
from flask import Blueprint, current_app, flash, jsonify, redirect, request, url_for
# 导入Flask版本号
from flask import __version__ as flask_version
# 导入Flask视图相关的MethodView类
from flask.views import MethodView
# 导入Flask - Allows相关的权限判断类
from flask_allows import Not, Permission
# 导入Flask - BabelPlus的翻译函数
from flask_babelplus import gettext as _
# 导入Flask - Login相关的当前用户和登录状态判断函数
from flask_login import current_user, login_fresh
# 导入pluggy的HookimplMarker
from pluggy import HookimplMarker

# 导入xfree的扩展、Celery实例和数据库实例
from xfree.extensions import allows, celery, db
# 导入用户搜索表单类
from xfree.forum.forms import UserSearchForm
# 导入论坛相关的模型类
from xfree.forum.models import Category, Forum, Post, Report, Topic
# 导入管理员相关的表单类
from xfree.admin.forms import (
    AddForumForm,
    AddGroupForm,
    AddUserForm,
    CategoryForm,
    EditForumForm,
    EditGroupForm,
    EditUserForm,
)
# 导入管理员相关的模型类
from xfree.admin.models import Setting, SettingsGroup
# 导入插件相关的模型类
from xfree.plugins.models import PluginRegistry, PluginStore
# 导入插件验证函数
from xfree.plugins.utils import validate_plugin
# 导入用户相关的模型类
from xfree.user.models import Group, Guest, User
# 导入表单相关的填充函数
from xfree.utils.forms import populate_settings_dict, populate_settings_form
# 导入一些工具函数和类
from xfree.utils.helpers import (
    FlashAndRedirect,
    get_online_users,
    redirect_or_next,
    register_view,
    render_template,
    time_diff,
    time_utcnow,
)
# 导入权限相关的类
from xfree.utils.requirements import (
    CanBanUser,
    CanEditUser,
    IsAdmin,
    IsAtleastModerator,
    IsAtleastSuperModerator,
)
# 导入xfree配置
from xfree.utils.settings import xfree_config

# 创建HookimplMarker实例
impl = HookimplMarker("xfree")
# 获取日志记录器
logger = logging.getLogger(__name__)


class ManagementSettings(MethodView):
    """
    管理设置视图类。

    用于处理管理设置页面的GET和POST请求，并且通过装饰器确保只有管理员用户才能访问这些页面。
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权访问管理设置"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def _determine_active_settings(self, slug, plugin):
        """
        确定哪些设置是活动的。

        :param slug: 可能是设置组的标识
        :param plugin: 可能是插件名称

        :return: 返回一个包含表单、旧设置、插件对象和活动导航信息的元组
        """
        # 如果slug为空，设置为"general"
        slug = slug if slug else "general"
        active_nav = {}
        plugin_obj = None
        if plugin is not None:
            # 根据插件名称查询插件对象，如果不存在则返回404错误
            plugin_obj = PluginRegistry.query.filter_by(name=plugin).first_or_404()
            active_nav.update(
                {"key": plugin_obj.name, "title": plugin_obj.name.title()}
            )
            # 获取插件的设置表单
            form = plugin_obj.get_settings_form()
            # 获取插件的旧设置
            old_settings = plugin_obj.settings

        elif slug is not None:
            # 根据slug查询设置组对象，如果不存在则返回404错误
            group_obj = SettingsGroup.query.filter_by(key=slug).first_or_404()
            active_nav.update({"key": group_obj.key, "title": group_obj.name})
            # 获取设置组的表单
            form = Setting.get_form(group_obj)()
            # 获取设置组的旧设置
            old_settings = Setting.get_settings(group_obj)

        return form, old_settings, plugin_obj, active_nav

    def get(self, slug=None, plugin=None):
        """
        处理GET请求，用于显示管理设置页面。

        :param slug: 可能是设置组的标识
        :param plugin: 可能是插件名称

        :return: 渲染管理设置页面的模板
        """
        form, old_settings, plugin_obj, active_nav = self._determine_active_settings(
            slug, plugin
        )
        # 查询所有设置组
        all_groups = SettingsGroup.query.all()
        # 查询所有启用的插件
        all_plugins = PluginRegistry.query.filter(
            db.and_(PluginRegistry.values!= None, PluginRegistry.enabled == True)
        ).all()
        # 填充表单
        form = populate_settings_form(form, old_settings)
        return render_template(
            "admin/settings.html",
            form=form,
            all_groups=all_groups,
            all_plugins=all_plugins,
            active_nav=active_nav,
        )

    def post(self, slug=None, plugin=None):
        """
        处理POST请求，用于保存管理设置。

        :param slug: 可能是设置组的标识
        :param plugin: 可能是插件名称

        :return: 渲染管理设置页面的模板
        """
        form, old_settings, plugin_obj, active_nav = self._determine_active_settings(
            slug, plugin
        )
        all_groups = SettingsGroup.query.all()
        all_plugins = PluginRegistry.query.filter(
            db.and_(PluginRegistry.values!= None, PluginRegistry.enabled == True)
        ).all()
        if form.validate_on_submit():
            # 根据表单和旧设置生成新设置
            new_settings = populate_settings_dict(form, old_settings)
            if plugin_obj is not None:
                # 如果有插件对象，更新插件的设置
                plugin_obj.update_settings(new_settings)
            else:
                # 否则更新设置组的设置
                Setting.update(settings=new_settings)
            # 显示设置保存成功的消息
            flash(_("设置已保存。"), "success")
        return render_template(
            "admin/settings.html",
            form=form,
            all_groups=all_groups,
            all_plugins=all_plugins,
            active_nav=active_nav,
        )



class ManageUsers(MethodView):
    """
    用户管理视图类。

    这个类中的视图方法用于处理用户管理相关的页面请求，
    并且有一个装饰器用于检查用户是否至少是版主权限，
    如果没有权限访问，会重定向并显示错误消息。
    同时定义了一个用户搜索表单。
    """
    decorators = [
        allows.requires(
            IsAtleastModerator,
            on_fail=FlashAndRedirect(
                message=_("你无权管理用户"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]
    form = UserSearchForm

    def get(self):
        """
        处理GET请求，用于显示用户管理页面。

        :return: 渲染用户管理页面的模板
        """
        # 获取请求中的页码，默认为1
        page = request.args.get("page", 1, type=int)
        form = self.form()
        # 分页查询用户列表，按照用户ID升序排列
        users = User.query.order_by(User.id.asc()).paginate(
            page=page, per_page=xfree_config["USERS_PER_PAGE"], error_out=False
        )
        return render_template("admin/users.html", users=users, search_form=form)

    def post(self):
        """
        处理POST请求，用于根据搜索条件显示用户列表。

        :return: 渲染用户管理页面的模板
        """
        page = request.args.get("page", 1, type=int)
        form = self.form()
        if form.validate():
            # 根据表单搜索条件获取分页的用户列表
            users = form.get_results().paginate(
                page=page, per_page=xfree_config["USERS_PER_PAGE"], error_out=False
            )
            return render_template(
                "admin/users.html", users=users, search_form=form
            )
        users = User.query.order_by(User.id.asc()).paginate(
            page=page, per_page=xfree_config["USERS_PER_PAGE"], error_out=False
        )
        return render_template("admin/users.html", users=users, search_form=form)



class EditUser(MethodView):
    """
    编辑用户视图类。

    这个类中的视图方法用于处理编辑用户相关的页面请求，
    并且有装饰器用于检查用户是否至少是版主且有编辑用户权限，
    如果没有权限访问，会重定向并显示错误消息。
    同时定义了编辑用户表单。
    """
    decorators = [
        allows.requires(
            IsAtleastModerator,
            CanEditUser,
            on_fail=FlashAndRedirect(
                message=_("你无权管理用户"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]
    form = EditUserForm

    def get(self, user_id):
        """
        处理GET请求，用于显示编辑用户页面。

        :param user_id: 要编辑的用户ID

        :return: 渲染编辑用户页面的模板
        """
        # 根据用户ID查询用户对象，如果不存在则返回404错误
        user = User.query.filter_by(id=user_id).first_or_404()
        form = self.form(user)
        member_group = db.and_(
            *[
                db.not_(getattr(Group, p))
                for p in ["admin", "mod", "super_mod", "banned", "guest"]
            ]
        )
        filt = db.or_(Group.id.in_(g.id for g in current_user.groups), member_group)
        if Permission(IsAtleastSuperModerator, identity=current_user):
            filt = db.or_(filt, Group.mod)
        if Permission(IsAdmin, identity=current_user):
            filt = db.or_(filt, Group.admin, Group.super_mod)
        if Permission(CanBanUser, identity=current_user):
            filt = db.or_(filt, Group.banned)
        group_query = Group.query.filter(filt)
        form.primary_group.query = group_query
        form.secondary_groups.query = group_query
        return render_template(
            "admin/user_form.html", form=form, title=_("编辑用户")
        )

    def post(self, user_id):
        """
        处理POST请求，用于保存编辑后的用户信息。

        :param user_id: 要编辑的用户ID

        :return: 渲染编辑用户页面的模板
        """
        user = User.query.filter_by(id=user_id).first_or_404()
        member_group = db.and_(
            *[
                db.not_(getattr(Group, p))
                for p in ["admin", "mod", "super_mod", "banned", "guest"]
            ]
        )
        filt = db.or_(Group.id.in_(g.id for g in current_user.groups), member_group)
        if Permission(IsAtleastSuperModerator, identity=current_user):
            filt = db.or_(filt, Group.mod)
        if Permission(IsAdmin, identity=current_user):
            filt = db.or_(filt, Group.admin, Group.super_mod)
        if Permission(CanBanUser, identity=current_user):
            filt = db.or_(filt, Group.banned)
        group_query = Group.query.filter(filt)
        form = EditUserForm(user)
        form.primary_group.query = group_query
        form.secondary_groups.query = group_query
        if form.validate_on_submit():
            form.populate_obj(user)
            user.primary_group_id = form.primary_group.data.id
            if form.password.data:
                user.password = form.password.data
            user.save(groups=form.secondary_groups.data)
            flash(_("用户已更新。"), "success")
            return redirect(url_for("admin.edit_user", user_id=user.id))
        return render_template(
            "admin/user_form.html", form=form, title=_("编辑用户")
        )


class DeleteUser(MethodView):
    """
    删除用户视图类。

    这个类中的视图方法用于处理删除用户相关的页面请求，
    并且有装饰器用于检查用户是否是管理员权限，
    如果没有权限访问，会重定向并显示错误消息。
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权管理用户"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def post(self, user_id=None):
        """
        处理POST请求，用于删除用户。

        :param user_id: 要删除的用户ID，如果为None则可能是批量删除

        :return: 根据操作结果返回相应的JSON数据或重定向
        """
        json = request.get_json(silent=True)
        if json is not None:
            ids = json.get("ids")
            if not ids:
                return jsonify(message="未提供用户ID。", category="error", status=404)
            data = []
            for user in User.query.filter(User.id.in_(ids)).all():
                if current_user.id == user.id:
                    continue
                if user.delete():
                    data.append(
                        {
                            "id": user.id,
                            "type": "delete",
                            "reverse": False,
                            "reverse_name": None,
                            "reverse_url": None,
                        }
                    )
            return jsonify(
                message=f"{len(data)}个用户已删除。",
                category="success",
                data=data,
                status=200,
            )
        user = User.query.filter_by(id=user_id).first_or_404()
        if current_user.id == user.id:
            flash(_("你不能删除自己。"), "danger")
            return redirect(url_for("admin.users"))
        user.delete()
        flash(_("用户已删除。"), "success")
        return redirect(url_for("admin.users"))


class AddUser(MethodView):
    """
    添加用户视图类。

    这个类中的视图方法用于处理添加用户相关的页面请求，
    并且有装饰器用于检查用户是否是管理员权限，
    如果没有权限访问，会重定向并显示错误消息。
    同时定义了添加用户表单。
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权管理用户"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]
    form = AddUserForm

    def get(self):
        """
        处理GET请求，用于显示添加用户页面。

        :return: 渲染添加用户页面的模板
        """
        return render_template(
            "admin/user_form.html", form=self.form(), title=_("添加用户")
        )

    def post(self):
        """
        处理POST请求，用于保存添加的用户信息。

        :return: 根据操作结果返回相应的重定向或渲染添加用户页面的模板
        """
        form = self.form()
        if form.validate_on_submit():
            form.save()
            flash(_("用户已添加。"), "success")
            return redirect(url_for("admin.users"))
        return render_template(
            "admin/user_form.html", form=form, title=_("添加用户")
        )



class BannedUsers(MethodView):
    """
    BannedUsers视图类，用于处理被封禁用户相关操作
    """
    decorators = [
        allows.requires(
            IsAtleastModerator,
            # 如果用户权限不足，通过FlashAndRedirect进行处理
            on_fail=FlashAndRedirect(
                message=_("你无权管理用户"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]
    form = UserSearchForm

    def get(self):
        """
        处理GET请求，用于获取被封禁用户列表并渲染页面

        获取请求中的页码（默认为1），使用定义的表单进行查询操作，
        查询被封禁且以封禁组为主要用户组的用户列表并进行分页，
        最后渲染管理界面中的被封禁用户页面并传递用户列表和搜索表单
        """
        page = request.args.get("page", 1, type=int)
        search_form = self.form()

        users = User.query.filter(
            Group.banned == True, Group.id == User.primary_group_id
        ).paginate(
            page=page, per_page=xfree_config["USERS_PER_PAGE"], error_out=False
        )

        return render_template(
            "admin/banned_users.html", users=users, search_form=search_form
        )

    def post(self):
        """
        处理POST请求，用于根据搜索表单获取被封禁用户列表并渲染页面

        获取请求中的页码（默认为1），如果表单验证通过，
        根据表单获取结果并分页查询被封禁且以封禁组为主要用户组的用户列表，
        最后渲染管理界面中的被封禁用户页面并传递用户列表和搜索表单。
        如果表单验证不通过，直接查询并渲染被封禁用户列表
        """
        page = request.args.get("page", 1, type=int)
        search_form = self.form()

        users = User.query.filter(
            Group.banned == True, Group.id == User.primary_group_id
        ).paginate(
            page=page, per_page=xfree_config["USERS_PER_PAGE"], error_out=False
        )

        if search_form.validate():
            users = search_form.get_results().paginate(
                page=page, per_page=xfree_config["USERS_PER_PAGE"], error_out=False
            )

            return render_template(
                "admin/banned_users.html", users=users, search_form=search_form
            )

        return render_template(
            "admin/banned_users.html", users=users, search_form=search_form
        )


class BanUser(MethodView):
    """
    BanUser视图类，用于处理封禁用户操作
    """
    decorators = [
        allows.requires(
            IsAtleastModerator,
            on_fail=FlashAndRedirect(
                message=_("你无权管理用户"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def post(self, user_id=None):
        """
        处理POST请求，用于封禁用户

        如果当前用户没有封禁用户的权限，显示错误消息并跳转到管理概览页面。
        如果是AJAX请求，根据提供的用户ID列表进行批量封禁操作，
        跳过当前用户和管理员（如果当前用户不是管理员），
        封禁成功的用户信息将被添加到返回数据中。
        如果是单个用户封禁操作，检查用户权限，不允许版主封禁管理员，
        根据封禁操作结果显示相应的提示消息，并跳转到被封禁用户管理页面或管理概览页面
        """
        if not Permission(CanBanUser, identity=current_user):
            flash(_("你没有封禁此用户的权限。"), "danger")
            return redirect(url_for("admin.overview"))

        # ajax request
        json = request.get_json(silent=True)
        if json is not None:
            ids = json.get("ids")
            if not ids:
                return jsonify(message="未提供用户ID。", category="error", status=404)

            data = []
            users = User.query.filter(User.id.in_(ids)).all()
            for user in users:
                # 不允许用户封禁自己，也不允许版主封禁管理员
                if (
                    current_user.id == user.id
                    or Permission(IsAdmin, identity=user)
                    and Permission(Not(IsAdmin), current_user)
                ):
                    continue

                elif user.ban():
                    data.append(
                        {
                            "id": user.id,
                            "type": "ban",
                            "reverse": "unban",
                            "reverse_name": _("解封"),
                            "reverse_url": url_for(
                                "admin.unban_user", user_id=user.id
                            ),
                        }
                    )

            return jsonify(
                message="{}个用户已被封禁。".format(len(data)),
                category="success",
                data=data,
                status=200,
            )

        user = User.query.filter_by(id=user_id).first_or_404()
        # 不允许版主封禁管理员
        if Permission(IsAdmin, identity=user) and Permission(
            Not(IsAdmin), identity=current_user
        ):
            flash(_("版主不能封禁管理员用户。"), "danger")
            return redirect(url_for("admin.overview"))

        if not current_user.id == user.id and user.ban():
            flash(_("用户现已被封禁。"), "success")
        else:
            flash(_("无法封禁用户。"), "danger")

        return redirect_or_next(url_for("admin.banned_users"))


class UnbanUser(MethodView):
    """
    UnbanUser视图类，用于处理解封用户操作
    """
    decorators = [
        allows.requires(
            IsAtleastModerator,
            on_fail=FlashAndRedirect(
                message=_("你无权管理用户"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def post(self, user_id=None):
        """
        处理POST请求，用于解封用户

        如果当前用户没有解封用户的权限，显示错误消息并跳转到管理概览页面。
        如果是AJAX请求，根据提供的用户ID列表进行批量解封操作，
        解封成功的用户信息将被添加到返回数据中。
        如果是单个用户解封操作，根据解封操作结果显示相应的提示消息，
        并跳转到用户管理页面或管理概览页面
        """
        if not Permission(CanBanUser, identity=current_user):
            flash(_("你没有解封此用户的权限。"), "danger")
            return redirect(url_for("admin.overview"))

        # ajax request
        json = request.get_json(silent=True)
        if json is not None:
            ids = json.get("ids")
            if not ids:
                return jsonify(message="未提供用户ID。", category="error", status=404)

            data = []
            for user in User.query.filter(User.id.in_(ids)).all():
                if user.unban():
                    data.append(
                        {
                            "id": user.id,
                            "type": "ban",
                            "reverse": "ban",
                            "reverse_name": _("封禁"),
                            "reverse_url": url_for(
                                "admin.ban_user", user_id=user.id
                            ),
                        }
                    )

            return jsonify(
                message=f"{len(data)}个用户已解封。",
                category="success",
                data=data,
                status=200,
            )

        user = User.query.filter_by(id=user_id).first_or_404()

        if user.unban():
            flash(_("用户现已解封。"), "success")
        else:
            flash(_("无法解封用户。"), "danger")

        return redirect_or_next(url_for("admin.users"))


class Groups(MethodView):
    """
    Groups视图类，用于处理用户组相关操作
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改用户组。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def get(self):
        """
        处理GET请求，用于获取用户组列表并渲染页面

        获取请求中的页码（默认为1），查询所有用户组并进行分页，
        最后渲染管理界面中的用户组页面并传递用户组列表
        """
        page = request.args.get("page", 1, type=int)

        groups = Group.query.order_by(Group.id.asc()).paginate(
            page=page, per_page=xfree_config["USERS_PER_PAGE"], error_out=False
        )

        return render_template("admin/groups.html", groups=groups)


class AddGroup(MethodView):
    """
    AddGroup视图类，用于处理添加用户组操作
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改用户组。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]
    form = AddGroupForm

    def get(self):
        """
        处理GET请求，用于渲染添加用户组页面
        """
        return render_template(
            "admin/group_form.html", form=self.form(), title=_("添加用户组")
        )

    def post(self):
        """
        处理POST请求，用于添加用户组

        如果表单验证通过，保存用户组信息，显示成功消息并跳转到用户组管理页面。
        如果表单验证不通过，渲染添加用户组页面并传递表单
        """
        form = AddGroupForm()
        if form.validate_on_submit():
            form.save()
            flash(_("用户组已添加。"), "success")
            return redirect(url_for("admin.groups"))

        return render_template(
            "admin/group_form.html", form=form, title=_("添加用户组")
        )


class EditGroup(MethodView):
    """
    EditGroup视图类，用于处理编辑用户组操作
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改用户组。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]
    form = EditGroupForm

    def get(self, group_id):
        """
        处理GET请求，用于渲染编辑用户组页面

        根据用户组ID查询用户组对象，如果不存在则返回404错误，
        使用查询到的用户组对象初始化表单，最后渲染编辑用户组页面并传递表单
        """
        group = Group.query.filter_by(id=group_id).first_or_404()
        form = self.form(group)
        return render_template(
            "admin/group_form.html", form=form, title=_("编辑用户组")
        )

    def post(self, group_id):
        """
        处理POST请求，用于保存编辑后的用户组信息

        根据用户组ID查询用户组对象，如果不存在则返回404错误，
        使用查询到的用户组对象初始化表单，如果表单验证通过，
        使用表单数据更新用户组对象，保存用户组信息，
        如果用户组是访客组，使访客缓存失效，显示成功消息并跳转到用户组管理页面。
        如果表单验证不通过，渲染编辑用户组页面并传递表单
        """
        group = Group.query.filter_by(id=group_id).first_or_404()
        form = EditGroupForm(group)

        if form.validate_on_submit():
            form.populate_obj(group)
            group.save()

            if group.guest:
                Guest.invalidate_cache()

            flash(_("用户组已更新。"), "success")
            return redirect(url_for("admin.groups", group_id=group.id))

        return render_template(
            "admin/group_form.html", form=form, title=_("编辑用户组")
        )



class DeleteGroup(MethodView):
    """
    DeleteGroup视图类，用于处理删除用户组操作
    只有管理员有权限进行操作，否则会重定向并显示错误消息
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改用户组。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def post(self, group_id=None):
        """
        处理POST请求，用于删除用户组

        如果是JSON请求：
            - 若未提供ids，返回错误信息
            - 如果ids中不包含标准组（1 - 6），则删除对应组并返回成功信息
            - 如果包含标准组，返回不允许删除标准组的错误信息

        如果提供了group_id：
            - 如果group_id小于等于6（标准组），显示不允许删除的提示并跳转到用户组管理页面
            - 如果group_id对应的组存在，删除该组并显示成功消息，然后跳转到用户组管理页面
            - 如果未提供group_id，显示未选择组的提示并跳转到用户组管理页面
        """
        json = request.get_json(silent=True)
        if json is not None:
            ids = json.get("ids")
            if not ids:
                return jsonify(message="未提供用户组ID。", category="error", status=404)

            # TODO: 消除魔法数字（这里指硬编码的1 - 6）
            if not (set(ids) & set(["1", "2", "3", "4", "5", "6"])):
                data = []
                for group in Group.query.filter(Group.id.in_(ids)).all():
                    group.delete()
                    data.append(
                        {
                            "id": group.id,
                            "type": "delete",
                            "reverse": False,
                            "reverse_name": None,
                            "reverse_url": None,
                        }
                    )

                return jsonify(
                    message="{}个用户组已删除。".format(len(data)),
                    category="success",
                    data=data,
                    status=200,
                )
            return jsonify(
                message=_("你不能删除标准用户组。"),
                category="danger",
                data=None,
                status=404,
            )

        if group_id is not None:
            if group_id <= 6:  # 存在6个标准组
                flash(
                    _(
                        "你不能删除标准用户组。尝试重命名吧。",
                        "danger",
                    )
                )
                return redirect(url_for("admin.groups"))

            group = Group.query.filter_by(id=group_id).first_or_404()
            group.delete()
            flash(_("用户组已删除。"), "success")
            return redirect(url_for("admin.groups"))

        flash(_("未选择用户组。"), "danger")
        return redirect(url_for("admin.groups"))


class Forums(MethodView):
    """
    Forums视图类，用于处理论坛相关操作
    只有管理员有权限进行操作，否则会重定向并显示错误消息
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改论坛。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def get(self):
        """
        处理GET请求，获取所有分类并按位置升序排序，然后渲染管理界面中的论坛页面并传递分类列表
        """
        categories = Category.query.order_by(Category.position.asc()).all()
        return render_template("admin/forums.html", categories=categories)


class EditForum(MethodView):
    """
    EditForum视图类，用于处理编辑论坛操作
    只有管理员有权限进行操作，否则会重定向并显示错误消息
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改论坛。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]
    form = EditForumForm

    def get(self, forum_id):
        """
        处理GET请求，用于渲染编辑论坛页面

        根据论坛ID查询论坛对象，如果不存在则返回404错误，
        使用查询到的论坛对象初始化表单，
        如果论坛有版主，将版主用户名用逗号连接并设置为表单的版主数据，否则设置为None，
        最后渲染编辑论坛页面并传递表单
        """
        forum = Forum.query.filter_by(id=forum_id).first_or_404()

        form = self.form(forum)

        if forum.moderators:
            form.moderators.data = ",".join(
                [user.username for user in forum.moderators]
            )
        else:
            form.moderators.data = None

        return render_template(
            "admin/forum_form.html", form=form, title=_("编辑论坛")
        )

    def post(self, forum_id):
        """
        处理POST请求，用于保存编辑后的论坛信息

        根据论坛ID查询论坛对象，如果不存在则返回404错误，
        使用查询到的论坛对象初始化表单，
        如果表单验证通过，保存论坛信息，显示成功消息并跳转到编辑论坛页面（传入论坛ID），
        如果表单验证不通过，
            - 如果论坛有版主，将版主用户名用逗号连接并设置为表单的版主数据，否则设置为None，
            - 渲染编辑论坛页面并传递表单
        """
        forum = Forum.query.filter_by(id=forum_id).first_or_404()

        form = self.form(forum)
        if form.validate_on_submit():
            form.save()
            flash(_("论坛已更新。"), "success")
            return redirect(url_for("admin.edit_forum", forum_id=forum.id))
        else:
            if forum.moderators:
                form.moderators.data = ",".join(
                    [user.username for user in forum.moderators]
                )
            else:
                form.moderators.data = None

        return render_template(
            "admin/forum_form.html", form=form, title=_("编辑论坛")
        )


class AddForum(MethodView):
    """
    AddForum视图类，用于处理添加论坛操作
    只有管理员有权限进行操作，否则会重定向并显示错误消息
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改论坛。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]
    form = AddForumForm

    def get(self, category_id=None):
        """
        处理GET请求，用于渲染添加论坛页面

        初始化添加论坛表单，
        将所有用户组按ID升序排序并设置为表单的用户组数据，
        如果提供了category_id，查询对应的分类并设置为表单的分类数据，
        最后渲染添加论坛页面并传递表单
        """
        form = self.form()

        form.groups.data = Group.query.order_by(Group.id.asc()).all()

        if category_id:
            category = Category.query.filter_by(id=category_id).first()
            form.category.data = category

        return render_template(
            "admin/forum_form.html", form=form, title=_("添加论坛")
        )

    def post(self, category_id=None):
        """
        处理POST请求，用于添加论坛

        初始化添加论坛表单，
        如果表单验证通过，保存论坛信息，显示成功消息并跳转到论坛管理页面，
        如果表单验证不通过，
            - 将所有用户组按ID升序排序并设置为表单的用户组数据，
            - 如果提供了category_id，查询对应的分类并设置为表单的分类数据，
            - 渲染添加论坛页面并传递表单
        """
        form = self.form()

        if form.validate_on_submit():
            form.save()
            flash(_("论坛已添加。"), "success")
            return redirect(url_for("admin.forums"))
        else:
            form.groups.data = Group.query.order_by(Group.id.asc()).all()
            if category_id:
                category = Category.query.filter_by(id=category_id).first()
                form.category.data = category

        return render_template(
            "admin/forum_form.html", form=form, title=_("添加论坛")
        )


class DeleteForum(MethodView):
    """
    DeleteForum视图类，用于处理删除论坛操作
    只有管理员有权限进行操作，否则会重定向并显示错误消息
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改论坛"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def post(self, forum_id):
        """
        处理POST请求，用于删除论坛

        根据论坛ID查询论坛对象，如果不存在则返回404错误，
        查询在该论坛下有帖子的用户，
        删除论坛及其相关用户，
        显示论坛已删除的成功消息并跳转到论坛管理页面
        """
        forum = Forum.query.filter_by(id=forum_id).first_or_404()

        involved_users = User.query.filter(
            Topic.forum_id == forum.id, Post.user_id == User.id
        ).all()

        forum.delete(involved_users)

        flash(_("论坛已删除。"), "success")
        return redirect(url_for("admin.forums"))


class AddCategory(MethodView):
    """
    AddCategory视图类，用于处理添加分类操作
    只有管理员有权限进行操作，否则会重定向并显示错误消息
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改分类。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]
    form = CategoryForm

    def get(self):
        """
        处理GET请求，用于渲染添加分类页面
        """
        return render_template(
            "admin/category_form.html", form=self.form(), title=_("添加分类")
        )

    def post(self):
        """
        处理POST请求，用于添加分类

        如果表单验证通过，保存分类信息，显示成功消息并跳转到论坛管理页面，
        如果表单验证不通过，渲染添加分类页面并传递表单
        """
        form = self.form()

        if form.validate_on_submit():
            form.save()
            flash(_("分类已添加。"), "success")
            return redirect(url_for("admin.forums"))

        return render_template(
            "admin/category_form.html", form=form, title=_("添加分类")
        )


class EditCategory(MethodView):
    """
    EditCategory视图类，用于处理编辑分类操作
    只有管理员有权限进行操作，否则会重定向并显示错误消息
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改分类。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]
    form = CategoryForm

    def get(self, category_id):
        """
        处理GET请求，用于渲染编辑分类页面

        根据分类ID查询分类对象，如果不存在则返回404错误，
        使用查询到的分类对象初始化表单，
        最后渲染编辑分类页面并传递表单
        """
        category = Category.query.filter_by(id=category_id).first_or_404()

        form = self.form(obj=category)

        return render_template(
            "admin/category_form.html", form=form, title=_("编辑分类")
        )

    def post(self, category_id):
        """
        处理POST请求，用于保存编辑后的分类信息

        根据分类ID查询分类对象，如果不存在则返回404错误，
        使用查询到的分类对象初始化表单，
        如果表单验证通过，使用表单数据更新分类对象，保存分类信息，显示成功消息，
        最后渲染编辑分类页面并传递表单
        """
        category = Category.query.filter_by(id=category_id).first_or_404()

        form = self.form(obj=category)

        if form.validate_on_submit():
            form.populate_obj(category)
            flash(_("分类已更新。"), "success")
            category.save()

        return render_template(
            "admin/category_form.html", form=form, title=_("编辑分类")
        )


class DeleteCategory(MethodView):
    """
    DeleteCategory视图类，用于处理删除分类操作
    只有管理员有权限进行操作，否则会重定向并显示错误消息
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改分类。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def post(self, category_id):
        """
        处理POST请求，用于删除分类

        根据分类ID查询分类对象，如果不存在则返回404错误，
        查询在该分类下有相关操作（论坛、主题、帖子）的用户，
        删除分类及其相关用户，
        显示分类及相关论坛已删除的成功消息并跳转到论坛管理页面
        """
        category = Category.query.filter_by(id=category_id).first_or_404()

        involved_users = User.query.filter(
            Forum.category_id == category.id,
            Topic.forum_id == Forum.id,
            Post.user_id == User.id,
        ).all()

        category.delete(involved_users)
        flash(_("分类及相关论坛已删除。"), "success")
        return redirect(url_for("admin.forums"))


class Reports(MethodView):
    """
    Reports视图类，用于处理报告相关操作
    只有版主及以上权限的用户有权限进行操作，否则会重定向并显示错误消息
    """
    decorators = [
        allows.requires(
            IsAtleastModerator,
            on_fail=FlashAndRedirect(
                message=_("你无权查看报告。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def get(self):
        """
        处理GET请求，获取所有报告并按ID升序排序分页，然后渲染管理界面中的报告页面并传递报告列表
        """
        page = request.args.get("page", 1, type=int)
        reports = Report.query.order_by(Report.id.asc()).paginate(
            page=page, per_page=xfree_config["USERS_PER_PAGE"], error_out=False
        )

        return render_template("admin/reports.html", reports=reports)


class UnreadReports(MethodView):
    """
    UnreadReports视图类，用于处理未读报告相关操作
    只有版主及以上权限的用户有权限进行操作，否则会重定向并显示错误消息
    """
    decorators = [
        allows.requires(
            IsAtleastModerator,
            on_fail=FlashAndRedirect(
                message=_("你无权查看报告。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def get(self):
        """
        处理GET请求，获取所有未读报告并按ID降序排序分页，然后渲染管理界面中的报告页面并传递报告列表
        """
        page = request.args.get("page", 1, type=int)
        reports = (
            Report.query.filter(Report.zapped == None)
           .order_by(Report.id.desc())
           .paginate(
                page=page, per_page=xfree_config["USERS_PER_PAGE"], error_out=False
            )
        )

        return render_template("admin/reports.html", reports=reports)


class MarkReportRead(MethodView):
    """
    MarkReportRead视图类，用于处理将报告标记为已读的操作。
    该视图类有装饰器来检查用户是否至少是版主权限，
    如果没有权限，会重定向并显示错误消息。
    """
    decorators = [
        allows.requires(
            IsAtleastModerator,
            on_fail=FlashAndRedirect(
                message=_("你无权查看报告。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def post(self, report_id=None):
        """
        处理POST请求，用于将报告标记为已读，有以下几种情况：

        1. 如果是AJAX请求：
            - 从请求中获取要标记的报告ID列表（ids）。
            - 如果没有提供ids，返回错误信息（404状态码）。
            - 对于每个提供的报告ID，将报告标记为已读，记录操作人（当前用户）和操作时间，
              并将操作信息添加到要返回的数据列表中。
            - 最后以JSON格式返回成功消息，包含已标记为已读的报告数量。

        2. 如果提供了单个report_id：
            - 根据report_id查询报告对象。
            - 如果报告已经被标记为已读，显示提示消息并进行相应的重定向操作。
            - 如果报告未读，将其标记为已读，记录操作人（当前用户）和操作时间，
              显示成功消息并进行相应的重定向操作。

        3. 如果没有提供report_id：
            - 查询所有未读的报告。
            - 将所有未读报告标记为已读，记录操作人（当前用户）和操作时间。
            - 提交数据库会话以保存更改。
            - 显示所有报告已标记为已读的成功消息并进行相应的重定向操作。
        """
        # AJAX请求
        json = request.get_json(silent=True)
        if json is not None:
            ids = json.get("ids")
            if not ids:
                return jsonify(message="未提供报告ID。", category="error", status=404)
            data = []

            for report in Report.query.filter(Report.id.in_(ids)).all():
                report.zapped_by = current_user.id
                report.zapped = time_utcnow()
                report.save()
                data.append(
                    {
                        "id": report.id,
                        "type": "read",
                        "reverse": False,
                        "reverse_name": None,
                        "reverse_url": None,
                    }
                )

            return jsonify(
                message="{}个报告已标记为已读。".format(len(data)),
                category="success",
                data=data,
                status=200,
            )

        # 标记单个报告为已读
        if report_id:
            report = Report.query.filter_by(id=report_id).first_or_404()
            if report.zapped:
                flash(
                    _("报告 %(id)s 已经被标记为已读。", id=report.id),
                    "success",
                )
                return redirect_or_next(url_for("admin.reports"))

            report.zapped_by = current_user.id
            report.zapped = time_utcnow()
            report.save()
            flash(_("报告 %(id)s 已标记为已读。", id=report.id), "success")
            return redirect_or_next(url_for("admin.reports"))

        # 标记所有报告为已读
        reports = Report.query.filter(Report.zapped == None).all()
        report_list = []
        for report in reports:
            report.zapped_by = current_user.id
            report.zapped = time_utcnow()
            report_list.append(report)

        db.session.add_all(report_list)
        db.session.commit()

        flash(_("所有报告已标记为已读。"), "success")
        return redirect_or_next(url_for("admin.reports"))


class DeleteReport(MethodView):
    """
    DeleteReport视图类，用于处理删除报告的操作。
    该视图类有装饰器来检查用户是否至少是版主权限，
    如果没有权限，会重定向并显示错误消息。
    """
    decorators = [
        allows.requires(
            IsAtleastModerator,
            on_fail=FlashAndRedirect(
                message=_("你无权查看报告。"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def post(self, report_id=None):
        """
        处理POST请求，用于删除报告，有以下几种情况：

        1. 如果是JSON请求：
            - 从请求中获取要删除的报告ID列表（ids）。
            - 如果没有提供ids，返回错误信息（404状态码）。
            - 对于每个提供的报告ID，尝试删除报告，如果删除成功，将操作信息添加到要返回的数据列表中。
            - 最后以JSON格式返回成功消息，包含已删除的报告数量。

        2. 如果提供了单个report_id：
            - 根据report_id查询报告对象。
            - 如果报告存在，删除该报告，显示报告已删除的成功消息并进行相应的重定向操作。
        """
        json = request.get_json(silent=True)
        if json is not None:
            ids = json.get("ids")
            if not ids:
                return jsonify(message="未提供报告ID。", category="error", status=404)

            data = []
            for report in Report.query.filter(Report.id.in_(ids)).all():
                if report.delete():
                    data.append(
                        {
                            "id": report.id,
                            "type": "delete",
                            "reverse": False,
                            "reverse_name": None,
                            "reverse_url": None,
                        }
                    )

            return jsonify(
                message="{}个报告已删除。".format(len(data)),
                category="success",
                data=data,
                status=200,
            )

        report = Report.query.filter_by(id=report_id).first_or_404()
        report.delete()
        flash(_("报告已删除。"), "success")
        return redirect_or_next(url_for("admin.reports"))


class CeleryStatus(MethodView):
    """
    CeleryStatus视图类，用于获取Celery状态。
    该视图类有装饰器来检查用户是否至少是版主权限，
    如果没有权限，会重定向并显示错误消息。
    """
    decorators = [
        allows.requires(
            IsAtleastModerator,
            on_fail=FlashAndRedirect(
                message=_("你无权访问管理设置"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def get(self):
        """
        处理GET请求，用于获取Celery的运行状态。

        通过Celery的控制检查来获取运行状态，
        如果检查过程中出现异常（捕获所有异常不太好，但这里只是简单处理），
        则认为Celery未运行。
        最后以JSON格式返回Celery的运行状态和200状态码。
        """
        celery_inspect = celery.control.inspect()
        try:
            celery_running = True if celery_inspect.ping() else False
        except Exception:
            # catching Exception is bad, and just catching ConnectionError
            # from redis is also bad because you can run celery with other
            # brokers as well.
            celery_running = False

        return jsonify(celery_running=celery_running, status=200)


class ManagementOverview(MethodView):
    """
    ManagementOverview视图类，用于展示管理概览页面。
    该视图类有装饰器来检查用户是否至少是版主权限，
    如果没有权限，会重定向并显示错误消息。
    """
    decorators = [
        allows.requires(
            IsAtleastModerator,
            on_fail=FlashAndRedirect(
                message=_("你无权访问管理面板"),
                level="danger",
                endpoint="forum.index",
            ),
        )
    ]

    def get(self):
        # 导入xfree版本号
        from xfree import __version__ as xfree_version
        """
        处理GET请求，用于获取管理概览信息并渲染页面。

        计算一些统计数据：
        1. 用户和用户组相关统计：
            - 封禁用户数量：通过查询用户表和用户组表，找到封禁用户组且为主用户组的用户数量。
            - 在线用户数量：如果未启用Redis，通过查询用户表中最近活跃时间来计算；
              如果启用了Redis，通过获取在线用户列表的长度来计算。
            - 未读报告数量：查询未被处理（zapped为None）的报告数量。

        2. 其他统计数据：
            - Python版本：从系统的版本信息中获取。
            - Celery版本、Flask版本、xfree版本：从相应的模块中获取版本号。
            - 插件列表：查询所有已注册的插件。

        最后将这些统计数据传递给模板进行渲染。
        """
        # 用户和用户组统计
        banned_users = User.query.filter(
            Group.banned == True, Group.id == User.primary_group_id
        ).count()
        if not current_app.config["REDIS_ENABLED"]:
            online_users = User.query.filter(User.lastseen >= time_diff()).count()
        else:
            online_users = len(get_online_users())

        unread_reports = (
            Report.query.filter(Report.zapped == None)
           .order_by(Report.id.desc())
           .count()
        )

        python_version = "{}.{}.{}".format(
            sys.version_info[0], sys.version_info[1], sys.version_info[2]
        )

        stats = {
            "current_app": current_app,
            "unread_reports": unread_reports,
            # 统计数据
            "all_users": User.query.count(),
            "banned_users": banned_users,
            "online_users": online_users,
            "all_groups": Group.query.count(),
            "report_count": Report.query.count(),
            "topic_count": Topic.query.count(),
            "post_count": Post.query.count(),
            # 组件
            "python_version": python_version,
            "celery_version": celery_version,
            "flask_version": flask_version,
            "xfree_version": xfree_version,
            # 插件
            "plugins": PluginRegistry.query.all(),
        }

        return render_template("admin/overview.html", **stats)


class PluginsView(MethodView):
    """
    PluginsView视图类，用于展示插件列表。
    该视图类有装饰器来检查用户是否是管理员权限，
    如果没有权限，会重定向并显示错误消息。
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改插件"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def get(self):
        """
        处理GET请求，用于获取所有插件并渲染插件管理页面。
        """
        plugins = PluginRegistry.query.all()
        return render_template("admin/plugins.html", plugins=plugins)


class EnablePlugin(MethodView):
    """
    EnablePlugin视图类，用于启用插件。
    该视图类有装饰器来检查用户是否是管理员权限，
    如果没有权限，会重定向并显示错误消息。
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改插件"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def post(self, name):
        """
        处理POST请求，用于启用插件。

        1. 首先验证插件名称。
        2. 根据插件名称查询插件对象，如果不存在则返回404错误。
        3. 如果插件已经启用，显示提示消息并跳转到插件管理页面。
        4. 如果插件未启用，将插件设置为启用状态并保存，
           显示插件已启用的成功消息（提示需要重启xfree）并跳转到插件管理页面。
        """
        validate_plugin(name)
        plugin = PluginRegistry.query.filter_by(name=name).first_or_404()

        if plugin.enabled:
            flash(
                _("插件 %(plugin)s 已经启用。", plugin=plugin.name), "info"
            )
            return redirect(url_for("admin.plugins"))

        plugin.enabled = True
        plugin.save()

        flash(
            _(
                "插件 %(plugin)s 已启用。请现在重启xfree。",
                plugin=plugin.name,
            ),
            "success",
        )
        return redirect(url_for("admin.plugins"))


class DisablePlugin(MethodView):
    """
    DisablePlugin视图类，用于禁用插件。
    该视图类有装饰器来检查用户是否是管理员权限，
    如果没有权限，会重定向并显示错误消息。
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改插件"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def post(self, name):
        """
        处理POST请求，用于禁用插件。

        1. 首先验证插件名称。
        2. 根据插件名称查询插件对象，如果不存在则返回404错误。
        3. 如果插件已经禁用，显示提示消息并跳转到插件管理页面。
        4. 如果插件未禁用，将插件设置为禁用状态并保存，
           显示插件已禁用的成功消息（提示需要重启xfree）并跳转到插件管理页面。
        """
        validate_plugin(name)
        plugin = PluginRegistry.query.filter_by(name=name).first_or_404()

        if not plugin.enabled:
            flash(
                _("插件 %(plugin)s 已经禁用。", plugin=plugin.name), "info"
            )
            return redirect(url_for("admin.plugins"))

        plugin.enabled = False
        plugin.save()
        flash(
            _(
                "插件 %(plugin)s 已禁用。请现在重启xfree。",
                plugin=plugin.name,
            ),
            "success",
        )
        return redirect(url_for("admin.plugins"))


class UninstallPlugin(MethodView):
    """
    UninstallPlugin视图类，用于卸载插件。
    该视图类有装饰器来检查用户是否是管理员权限，
    如果没有权限，会重定向并显示错误消息。
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改插件"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def post(self, name):
        """
        处理POST请求，用于卸载插件。

        1. 首先验证插件名称。
        2. 根据插件名称查询插件对象，如果不存在则返回404错误。
        3. 删除与该插件相关的插件存储记录（PluginStore）。
        4. 提交数据库会话以保存更改。
        5. 显示插件已卸载的成功消息并跳转到插件管理页面。
        """
        validate_plugin(name)
        plugin = PluginRegistry.query.filter_by(name=name).first_or_404()
        PluginStore.query.filter_by(plugin_id=plugin.id).delete()
        db.session.commit()
        flash(_("插件已卸载。"), "success")
        return redirect(url_for("admin.plugins"))


class InstallPlugin(MethodView):
    """
    InstallPlugin视图类，用于处理插件安装操作
    只有管理员有权限进行操作，否则会重定向并显示错误消息
    """
    decorators = [
        allows.requires(
            IsAdmin,
            on_fail=FlashAndRedirect(
                message=_("你无权修改插件"),
                level="danger",
                endpoint="admin.overview",
            ),
        )
    ]

    def post(self, name):
        """
        处理POST请求，用于安装插件

        1. 首先验证插件名称，并获取插件模块
        2. 根据插件名称查询插件对象，如果不存在则返回404错误
        3. 如果插件未启用，显示错误消息并跳转到插件管理页面
        4. 如果插件已启用，为插件添加设置（从插件模块中获取），
           显示插件已安装的成功消息并跳转到插件管理页面
        """
        plugin_module = validate_plugin(name)
        plugin = PluginRegistry.query.filter_by(name=name).first_or_404()

        if not plugin.enabled:
            flash(
                _(
                    "无法安装插件。请先启用 '%(plugin)s' 插件。",
                    plugin=plugin.name,
                ),
                "danger",
            )
            return redirect(url_for("admin.plugins"))

        plugin.add_settings(plugin_module.SETTINGS)
        flash(_("插件已安装。"), "success")
        return redirect(url_for("admin.plugins"))


@impl(tryfirst=True)
def xfree_load_blueprints(app):
    """
    用于在Flask应用中加载管理相关的蓝图

    1. 创建一个名为"admin"的蓝图
    2. 在蓝图的每个请求之前检查用户登录是否为最新状态，
       如果不是则让用户重新认证
    3. 注册各类视图函数到蓝图的不同路由上
    4. 将蓝图注册到Flask应用，使用配置中的管理路径前缀
    """
    management = Blueprint("admin", __name__)

    @management.before_request
    def check_fresh_login():
        """
        检查当前用户的登录是否为最新状态，
        如果不是则返回重新认证的结果
        """
        if not login_fresh():
            return current_app.login_manager.needs_refresh()

    # Categories（分类相关操作）
    register_view(
        management,
        routes=["/category/add"],
        view_func=AddCategory.as_view("add_category")
    )
    register_view(
        management,
        routes=["/category/<int:category_id>/delete"],
        view_func=DeleteCategory.as_view("delete_category")
    )
    register_view(
        management,
        routes=["/category/<int:category_id>/edit"],
        view_func=EditCategory.as_view("edit_category")
    )

    # Forums（论坛相关操作）
    register_view(
        management,
        routes=["/forums/add", "/forums/<int:category_id>/add"],
        view_func=AddForum.as_view("add_forum")
    )
    register_view(
        management,
        routes=["/forums/<int:forum_id>/delete"],
        view_func=DeleteForum.as_view("delete_forum")
    )
    register_view(
        management,
        routes=["/forums/<int:forum_id>/edit"],
        view_func=EditForum.as_view("edit_forum")
    )
    register_view(management, routes=["/forums"], view_func=Forums.as_view("forums"))

    # Groups（用户组相关操作）
    register_view(
        management, routes=["/groups/add"], view_func=AddGroup.as_view("add_group")
    )
    register_view(
        management,
        routes=["/groups/<int:group_id>/delete", "/groups/delete"],
        view_func=DeleteGroup.as_view("delete_group")
    )
    register_view(
        management,
        routes=["g/roups/<int:group_id>/edit"],
        view_func=EditGroup.as_view("edit_group")
    )
    register_view(management, routes=["/groups"], view_func=Groups.as_view("groups"))

    # Plugins（插件相关操作）
    register_view(
        management,
        routes=["/plugins/<path:name>/disable"],
        view_func=DisablePlugin.as_view("disable_plugin")
    )
    register_view(
        management,
        routes=["/plugins/<path:name>/enable"],
        view_func=EnablePlugin.as_view("enable_plugin")
    )
    register_view(
        management,
        routes=["/plugins/<path:name>/install"],
        view_func=InstallPlugin.as_view("install_plugin")
    )
    register_view(
        management,
        routes=["/plugins/<path:name>/uninstall"],
        view_func=UninstallPlugin.as_view("uninstall_plugin")
    )
    register_view(
        management, routes=["/plugins"], view_func=PluginsView.as_view("plugins")
    )

    # Reports（报告相关操作）
    register_view(
        management,
        routes=["/reports/<int:report_id>/delete", "/reports/delete"],
        view_func=DeleteReport.as_view("delete_report")
    )
    register_view(
        management,
        routes=["/reports/<int:report_id>/markread", "/reports/markread"],
        view_func=MarkReportRead.as_view("report_markread")
    )
    register_view(
        management,
        routes=["/reports/unread"],
        view_func=UnreadReports.as_view("unread_reports")
    )
    register_view(management, routes=["/reports"], view_func=Reports.as_view("reports"))

    # Settings（设置相关操作）
    register_view(
        management,
        routes=["/settings", "/settings/<path:slug>", "/settings/plugin/<path:plugin>"],
        view_func=ManagementSettings.as_view("settings")
    )

    # Users（用户相关操作）
    register_view(
        management, routes=["/users/add"], view_func=AddUser.as_view("add_user")
    )
    register_view(
        management,
        routes=["/users/banned"],
        view_func=BannedUsers.as_view("banned_users")
    )
    register_view(
        management,
        routes=["/users/ban", "/users/<int:user_id>/ban"],
        view_func=BanUser.as_view("ban_user")
    )
    register_view(
        management,
        routes=["/users/delete", "/users/<int:user_id>/delete"],
        view_func=DeleteUser.as_view("delete_user")
    )
    register_view(
        management,
        routes=["/users/<int:user_id>/edit"],
        view_func=EditUser.as_view("edit_user")
    )
    register_view(
        management,
        routes=["/users/unban", "/users/<int:user_id>/unban"],
        view_func=UnbanUser.as_view("unban_user")
    )
    register_view(management, routes=["/users"], view_func=ManageUsers.as_view("users"))
    register_view(
        management,
        routes=["/celerystatus"],
        view_func=CeleryStatus.as_view("celery_status")
    )
    register_view(
        management, routes=["/"], view_func=ManagementOverview.as_view("overview")
    )
    # Plugins（插件相关操作）
    app.register_blueprint(management, url_prefix=app.config["ADMIN_URL_PREFIX"])